package com.googlecode.imanager.swing;

import java.awt.Toolkit;
import java.awt.Window;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.Queue;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

import com.googlecode.imanager.client.Application;
import com.googlecode.imanager.client.Document;
import com.googlecode.imanager.client.Label;
import com.googlecode.imanager.client.Manager;
import com.googlecode.imanager.client.Panel;
import com.googlecode.imanager.client.Picture;
import com.googlecode.imanager.client.bridge.BridgeType;
import com.googlecode.imanager.client.form.Button;
import com.googlecode.imanager.client.form.CheckBox;
import com.googlecode.imanager.client.form.ComboBox;
import com.googlecode.imanager.client.form.ListBox;
import com.googlecode.imanager.client.form.RadioButton;
import com.googlecode.imanager.client.form.TextArea;
import com.googlecode.imanager.client.form.TextBox;
import com.googlecode.imanager.client.io.HttpRequest;
import com.googlecode.imanager.client.layout.ScrollBox;
import com.googlecode.imanager.client.util.Dimension;
import com.googlecode.imanager.core.base.AbstractApplication;
import com.googlecode.imanager.core.base.DefaultImage;
import com.googlecode.imanager.core.base.DefaultManager;
import com.googlecode.imanager.swing.form.SwingButton;
import com.googlecode.imanager.swing.form.SwingCheckBox;
import com.googlecode.imanager.swing.form.SwingComboBox;
import com.googlecode.imanager.swing.form.SwingListBox;
import com.googlecode.imanager.swing.form.SwingRadioButton;
import com.googlecode.imanager.swing.form.SwingTextArea;
import com.googlecode.imanager.swing.form.SwingTextBox;
import com.googlecode.imanager.swing.layout.SwingScrollBox;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public class SwingApplication extends AbstractApplication {
    
    private static final Object INVALID_IMAGE = new Object();

    private Queue<SwingDocument> documentsToUpdate;
    private static SwingPainter painter = new SwingPainter();
    
    public SwingApplication(DefaultManager manager, Application application, OutputStream output) {
        super(manager, application, output);
        documentsToUpdate = new ArrayDeque<SwingDocument>();
    }

    @Override
    public BridgeType getImplementationType() {
        return BridgeType.SWING;
    }

    @Override
    protected void initialize() {
        registerImplType(Panel.class, SwingPanel.class);
        registerImplType(Document.class, SwingDocument.class);
        registerImplType(Label.class, SwingLabel.class);
        registerImplType(Picture.class, SwingPicture.class);
        
        // package form
        registerImplType(Button.class, SwingButton.class);
        registerImplType(TextBox.class, SwingTextBox.class);
        registerImplType(TextArea.class, SwingTextArea.class);
        registerImplType(ComboBox.class, SwingComboBox.class);
        registerImplType(ListBox.class, SwingListBox.class);
        registerImplType(CheckBox.class, SwingCheckBox.class);
        registerImplType(RadioButton.class, SwingRadioButton.class);

        // package layout
        registerImplType(ScrollBox.class, SwingScrollBox.class);
    }

    public Window getTopLevelWindow() {
        SwingDocument document = getTopLevelDocument();
        if (document == null){
            return null;
        }
        return document.getTargetWindow();
    }

    public SwingDocument getTopLevelDocument() {
        for (Document document : getApplication().getDocuments()){
            if (document.isVisible()){
                return (SwingDocument) Manager.getImpl(document);
            }
        }
        return null;
    }

    public void addDocumentToUpdate(SwingDocument document){
        synchronized (documentsToUpdate) {
            if (!documentsToUpdate.contains(document)){
                documentsToUpdate.add(document);
            }
        }
    }
    
    public boolean addDocumentToUpdateIfProcessing(SwingDocument document){
        synchronized (documentsToUpdate) {
            boolean result = !documentsToUpdate.isEmpty();
            if (result && !documentsToUpdate.contains(document)){
                documentsToUpdate.add(document);
            }
            return result;
        }
    }
    
    @Override
    protected void afterGenerateBridge(Document document) {
        super.afterGenerateBridge(document);
        SwingDocument target;
        for (;;) {
            synchronized (documentsToUpdate) {
                target = documentsToUpdate.poll();
            }
            if (target != null){
                target.updateDocumentVisibility();
            } else {
                break;
            }
        }
    }

    @Override
    public void add(Document document) {
    }

    @Override
    public void remove(Document document) {
    }

    public Dimension getScreenSize() {
        java.awt.Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        return new Dimension(d.width, d.height);
    }
    
    public void handleError(Throwable e) {
        e.printStackTrace();
        showErrorDialog("Error", null, e);
    }

    public void showErrorDialog(String title, String message, Throwable e) {
        if (e != null){
            // TODO melhorar mensagem
            message = e.toString();
        }
        JOptionPane.showMessageDialog(getTopLevelWindow(), message, title, JOptionPane.ERROR_MESSAGE);
    }
    
    public void showWarningDialog(String title, String message) {
        JOptionPane.showMessageDialog(getTopLevelWindow(), message, title, JOptionPane.WARNING_MESSAGE);
    }
    
    public void showMessageDialog(String title, String message) {
        JOptionPane.showMessageDialog(getTopLevelWindow(), message, title, JOptionPane.INFORMATION_MESSAGE);
    }

    public String showInputDialog(String title, String message) {
        return JOptionPane.showInputDialog(getTopLevelWindow(), message, title, JOptionPane.QUESTION_MESSAGE); 
    }
    
    public boolean showQuestionDialog(String title, String message) { 
        return JOptionPane.showConfirmDialog(getTopLevelWindow(), message, title, 
                JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION;
    }
 
    @Override
    public void loadImageContent(DefaultImage image) {
        Object cache = image.getCachedContent();
        boolean changed = image.isPathChanged();
        
        if (changed || cache != INVALID_IMAGE){
            
            if (changed || !(cache instanceof ImageIcon)){
                URL url = getURLFromImage(image);
                
                if (url == null){
                    image.setCachedContent(INVALID_IMAGE);
                } else {                
                    try {
                        image.setCachedContent(new ImageIcon(url));
                    } catch (Exception e){
                        image.setCachedContent(INVALID_IMAGE);
                    }
                }
            }
            
            image.setPathChanged(false);
        }
    }

    public void httpCall(HttpRequest request) {}

    public SwingPainter getPainter() {
        return painter;
    }

}
